その他(中級)                               


■ インクリメント型エンコーダ読込                                                   


  <試作品仕様>
  ・A相とB相からなるインクリメント型エンコーダ出力を読み込む
  ・C.W.(時計まわり) 、C.C.W.(反時計まわり)の 回転方向はA相パルスの立上りにおけるB相の極性により判別する。
  ・エンコーダA相からのパルスの数をカウントして液晶に表示する。
  ・液晶への表示は HEXスイッチの設定値により カウントを逓倍して表示する

   HEXスイッチのメモリ   0 1 2 3 4 5 6 7 8 9 A B C D E F
 b3 b2 b1 b0  0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
N[倍] 1 10 100 1000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000

  ・0.25msec毎にA相の検出をおこない チャタリングが安定したらB相を読み込み回転方向を検出する。
  ・C.W.(時計まわり)にエンコーダのツマミを回したらカウント数が増加し、 、C.C.W.(反時計まわり)に回したらカウント数は減少すること。
  ・表示カウント数の最少値は0とする。


   
  <試作品回路図>(→回路図のPDFファイル
   ・ dsPIC4013をつかった場合の回路図を以下に示します。
   ・ エンコーダは秋月電子で販売されている インクリメント型エンコーダ  アルファ EC16B (RE16F-40E3-L(A)-24P相当)です。

 




<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています

 
    

          

   <プログラム例>
//*******************************************************************
// 手動インクリメント型エンコーダ読込
//      dsPIC4013
//*******************************************************************


#include <p30f4013.h>
#include <timer.h>
#include <ports.h>
#include        "1lcd_lib_C30.h"

#define b0      PORTBbits.RB5
#define b1      PORTBbits.RB4
#define b2      PORTBbits.RB3
#define b3      PORTBbits.RB2

_FOSC(CSW_FSCM_OFF &    // クロック切り替えなし、フェールセイフクロックモニタなし
                HS2_PLL16               //外部発振子周波数 × postscaler ×  PLL:16倍  → 10MHz × 1/2 × 16 = 80MHz
                );
_FWDT(WDT_OFF);                 //ウォッチドックタイマ:OFF        

_FBORPOR(PBOR_ON &              //ブラウンアウトリセット機能:ON
                BORV42 &                //ブラウンアウト電圧:4.2V
//              BORV_42 &               //ブラウンアウト電圧:4.2V  (旧 config 記載形式) 
                PWRT_64 &               //パワーオンリセットタイマ64msec
                MCLR_EN         //MCLR機能:ON
                );
_FGS(CODE_PROT_OFF);    //コードプロテクト:OFF


unsigned char dummy = ' ';
signed long Count = 0;  //FF入力周波数(エンコダカウント数 24パルス/回転) 32bit
unsigned int Mag = 1;   //エンコーダカウント数の周波数換算倍率

unsigned char AswCount = 0;     //A相0検出回数
unsigned char nAswCount = 0;    //A相1検出回数
unsigned char Asw;
unsigned char Rising;


char Buf[17];                                                   //文字列のバッファー用レジスタ


void delay_ms(unsigned int N)   //1msec遅延関数
{
        __delay32(Clock/4000*N);        //1msecのウェイト数: 80,000,000/4000 = 20,000
}


void Mag_Func()         //エンコーダカウント数−周波数倍率検出   //HEXスイッチ読み込み
{
        if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 1))Mag = 1;    //0     
        else if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 0))Mag = 10;      //1
        else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 1))Mag = 100;     //2
        else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 0))Mag = 1000;    //3
        else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 1))Mag = 10000;   //4
        else Mag = 10000;       //3
}


void _ISR _T1Interrupt(void)    //液晶表示  
{
        IFS0bits.T1IF = 0;                      //IFS0レジスタの T1IF(タイマ2の割込み検出)フラグリセット

        lcd_clear();                                            // 全消去
        sprintf(Buf,"Count=%ld",Count);//arguementがないと遅い  C30のバグ?
        lcd_str(Buf);
        lcd_cmd(0xC0);                                  //2行目の先頭へ
        sprintf(Buf,"*%u(multiply)",Mag);  //文字列としてバッファーに収納
        lcd_str(Buf);           
}




void Encode()           //エンコーダ読み込み
{
        Mag_Func();     //エンコーダ倍率
        if(PORTAbits.RA11 == 0) AswCount++;     //A相検出値が0なら AswCountをインクリメント
        else AswCount = 0;
        if(AswCount >= 8)
        {
                Asw = 0;        //AswCount = 8 の時 A相は0である。
                AswCount = 8;
        }

        if(PORTAbits.RA11 == 1)nAswCount++;     //A相検出値が1なら nAswCountをインクリメント
        else nAswCount = 0;
        if(nAswCount >= 8)
        {
                if(Asw == 0)Rising = 1;         //A相のパルスの立上り検出
                Asw = 1;        //nAswCount =  8 の時 A相は0である。
                nAswCount = 8;
        }

        if(Rising == 1) //A相パルスが立上った場合
        {
                Rising = 0;
                
        
                if(PORTDbits.RD9 == 0)
                {
                        Count = Count + Mag;    //C.W.の場合
                        if(Count >= 1000000)Count = 1000000;    //最大 1000000
                }
                else
                {
                        Count = Count - Mag;            //C.C.W.の場合
                        if(Count <= 0) Count = 0;
                }
        }


                __delay32(5000);        //0.25msec(読み込み)

}




int main(void)
{

        TRISA = 0xFFFF;
        ADPCFG = 0xFFFF;        //デジタルポートに設定
        TRISB = 0x003C; //
        
      
        TRISD = 0x0200;         //RD9: in
        TRISF = 0;

        LATFbits.LATF4 = 1;             //JK FF Q1 Clear Port → 1
        LATFbits.LATF5 = 1;             //JK FF Q2 Clear Port → 1

//T1タイマ         液晶表示
        OpenTimer1(
                        T1_ON   &       //タイマ1:ON
                        T1_GATE_OFF     &       //ゲート制御(信号がある時だけタイマが動作)OFF
                        T1_PS_1_256     &       //プリスケーラ 
                        T1_SYNC_EXT_OFF &       //外部同期タイマはタイマ1のみ
                        T1_SOURCE_INT,
                        23438           //300msec / 0.05μsec / 256 = 23437.5
                        );





        lcd_init();                                                     // LCD初期化

        lcd_cmd(0b00001100);                            // カーソル:OFF  ブリンク:OFF

        lcd_clear();                                            // 全消去
        sprintf(Buf,"Encoder %c",dummy);//arguementがないと遅い  C30のバグ?
        lcd_str(Buf);
                                                //液晶表示
        lcd_cmd(0xC0);                                  //2目表示行目の先頭へ
        sprintf(Buf,"Start !! %c",dummy);  //文字列としてバッファーに収納
        lcd_str(Buf);                                   // 開始メッセージ2行

        delay_ms(1000); 

        ConfigIntTimer1(T1_INT_PRIOR_2 & T1_INT_ON );   //割込みレベル2 連結タイマ1割込みON
        EnableIntT1;
                                                //割込み許可


        while(1)
        {
                Encode();
        }


        return 0;
}


//*************************************************************************
//インクルードファイル    1lcd_lib_C30.h
//このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、
//C30コンパイラ対応等でに変更したものです。
//*************************************************************************

#include "p30f4013.h"

#define Clock   80000000        // 単位はHzで指定

// LCDポート設定
#define lcd_port_DB7    LATBbits.LATB12 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定
#define lcd_port_DB6    LATBbits.LATB11 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定
#define lcd_port_DB5    LATBbits.LATB10 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定
#define lcd_port_DB4    LATBbits.LATB9  //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定
#define lcd_stb                 LATFbits.LATF0  //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定  
#define lcd_rs                  LATFbits.LATF1  //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定

void lcd_out(char code, char flag);
void lcd_data(char asci);
void lcd_cmd(char cmd);
void lcd_clear(void);
void lcd_init(void);
void lcd_str(char *str);


//**************************************************************************
//インクルードファイル    1lcd_lib_C30.c
//このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、
//C30コンパイラ対応等で変更したものです。
//**************************************************************************

///////////////////////////////////////////////
//  液晶表示器制御ライブラリ for C30コンパイラー
//  内蔵関数は以下
//    lcd_init()    ----- 初期化
//    lcd_cmd(cmd)  ----- コマンド出力
//    lcd_data(chr) ----- 1文字表示出力
//    lcd_clear()   ----- 全消去
//    lcd_str(str*) ----- 文字列表示 
//////////////////////////////////////////////

#include        "1lcd_lib_C30.h"
unsigned int _1usec;    // 1μsec待つに必要なウェイト回数
unsigned int _50usec;   //50μsec待つに必要なウェイト回数
unsigned long N_msec;   // 1msec待つに必要なウェイト回数



//////// データ出力サブ関数
void lcd_out(char code, char flag)
{
        if(code & 0b10000000)lcd_port_DB7 = 1;  //LCDのDB7への出力セット
        else lcd_port_DB7 = 0;
        if(code & 0b01000000)lcd_port_DB6 = 1;  //LCDのDB6への出力セット
        else lcd_port_DB6 = 0;
        if(code & 0b00100000)lcd_port_DB5 = 1;  //LCDのDB5への出力セット
        else lcd_port_DB5 = 0;
        if(code & 0b00010000)lcd_port_DB4 = 1;  //LCDのDB4への出力セット
        else lcd_port_DB4 = 0;

        if (flag == 0)
                lcd_rs = 1;                     // 表示データの場合
        else
                lcd_rs = 0;                     // コマンドデータの場合

        __delay32(_1usec);              //1μsecウェイト
                
        lcd_stb = 1;                    // strobe(E) ON (Enable)
                        
        __delay32(_1usec);              // 1μsec : strobe信号の幅

        lcd_stb = 0;                    // reset strobe
}

//////// 1文字表示関数
void lcd_data(char asci)
{
        lcd_out(asci, 0);               // 上位4ビット出力
        lcd_out(asci<<4, 0);    // 下位4ビット出力
        __delay32(_50usec);             //50μsecウェイト
}

/////// コマンド出力関数
void lcd_cmd(char cmd)
{
        lcd_out(cmd, 1);                // 上位4ビット出力
        lcd_out(cmd<<4, 1);             // 下位4ビット出力
        if((cmd & 0x03) != 0)   // clear Homeの場合
        __delay32(2*N_msec);    //      2msec待ち
        else
        __delay32(_50usec);             //50μsecウェイト    
}

/////// 全消去関数
void lcd_clear(void)
{
        lcd_cmd(0x01);                  // 初期化コマンド出力
//      __delay32(15*N_msec);   //15msecウェイト
}

/////// 文字列出力関数
void lcd_str(char* str)      
{
        while(*str)                             //文字列終端の '\0'を検出するまで
        {
                lcd_data(*str);         // 1文字表示
                str++;                          //ポインタをインクリメント                          
        }       
}


/////// 初期化関数
void lcd_init(void)
{
        _1usec =(unsigned int)( Clock / 4000000);       // 1μsecに要するウェイト回数
                                                                                                //__delay32(N) : Nが11以下の場合でも11回ウェイト
        _50usec = (unsigned int)(Clock / 4000000 * 50); //50μescに要するウェイト回数

        N_msec = (unsigned long int)(Clock / 4000);             // 1msecに要するウェイト回数
                                                                                                        // = Clock / 4000000*1000
        __delay32(20*N_msec);   //20msecウェイト
        lcd_out(0x30, 1);               // 8bit mode set
        __delay32(5*N_msec);    //5msecウェイト
        lcd_out(0x30, 1);               // 8bit mode set
        __delay32(N_msec);              //1msecウェイト
        lcd_out(0x30, 1);               // 8bit mode set
        __delay32(N_msec);              //1msecウェイト
        lcd_out(0x20, 1);               // 4bit mode set
        __delay32(N_msec);              //1msecウェイト
        lcd_cmd(0x2E);                  // DL=0 4bit mode
        lcd_cmd(0x08);                  // display off C=D=B=0
        lcd_cmd(0x0D);                  // display on C=D=1 B=0
        lcd_cmd(0x06);                  // entry I/D=1 S=0
        lcd_cmd(0x02);                  // cursor home
}





<動作結果>

逓倍   液晶画面
上段: カウント表示
下段: 倍率
逓倍率 = 1
逓倍率 = 10
逓倍率 = 100
逓倍率 = 1000
逓倍率 = 10000


 


■ パルスジェネレータ(0.5Hz〜200KHz)

 <試作品仕様>
  ・周波数: 1.0Hz〜200KHz Duty:50%の矩形波パルスを発生すること。
  ・周波数の設定は手動インクリメント型エンコーダで行えること。 
  ・周波数設定は ×1、×10、×100、×1000、×10000の 逓倍がHEXスイッチでおこなえること。
  ・周波数設定は0.5Hz単位でおこなえること。

 
  <試作品回路図>(→回路図のPDFファイル
   ・ dsPIC4013をつかった場合の回路図を以下に示します。
   ・ エンコーダは 秋月電子で販売されている インクリメント型エンコーダ  アルファ EC16B (RE16F-40E3-L(A)-24P相当)です。



<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています




   <プログラム例>
//*******************************************************************
// パルスジェネレータ(0.5Hz 〜 200KHz) 
//    dsPIC 16bit タイマ   dsPIC4013
//★ ハード(JK フリップフロップ 74HC107)で1/2に分周しているので PIC単独での出力周波数は(1Hz〜400KHz)
//*******************************************************************


#include <p30f4013.h>
#include <timer.h>
#include <ports.h>
#include        "1lcd_lib_C30.h"

#define b0      PORTBbits.RB5
#define b1      PORTBbits.RB4
#define b2      PORTBbits.RB3
#define b3      PORTBbits.RB2

_FOSC(CSW_FSCM_OFF &    // クロック切り替えなし、フェールセイフクロックモニタなし
                HS2_PLL16               //外部発振子周波数 × postscaler ×  PLL:16倍  → 10MHz × 1/2 × 16 = 80MHz
                );
_FWDT(WDT_OFF);                 //ウォッチドックタイマ:OFF        

_FBORPOR(PBOR_ON &              //ブラウンアウトリセット機能:ON
                BORV42 &                //ブラウンアウト電圧:4.2V
//              BORV_42 &               //ブラウンアウト電圧:4.2V  (旧 config 記載形式) 
                PWRT_64 &               //パワーオンリセットタイマ64msec
                MCLR_EN         //MCLR機能:ON
                );
_FGS(CODE_PROT_OFF);    //コードプロテクト:OFF


unsigned char dummy = ' ';
signed long Freq = 2;   //FF入力周波数(エンコダカウント数 24パルス/回転) 32bit
unsigned int Mag = 1;   //エンコーダカウント数の周波数換算倍率
unsigned int Duty_Count16 = 1000;       //タイマ2の周期設定値(=FF入力周期[μsec]×20) 16bit
unsigned long Duty_Count32 = 1000;      //タイマ2の周期設定値(=FF入力周期[μsec]×20) 32bit 
unsigned char AswCount = 0;     //A相0検出回数
unsigned char nAswCount = 0;    //A相1検出回数
unsigned char Asw;
unsigned char Rising;
unsigned long Nduty;    //T23のduty設定整数
int Quot = 0,Quot0 = 0;
unsigned int Remain = 10000,Remain0 = 10000;
int N ;

char Buf[17];                                                   //文字列のバッファー用レジスタ


void delay_ms(unsigned int N)   //1msec遅延関数
{
        __delay32(Clock/4000*N);        //1msecのウェイト数: 80,000,000/4000 = 20,000
}


void Mag_Func()         //エンコーダカウント数−周波数倍率検出   //HEXスイッチ読み込み
{
        if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 1))Mag = 1;    //0     
        else if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 0))Mag = 10;      //1
        else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 1))Mag = 100;     //2
        else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 0))Mag = 1000;    //3
        else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 1))Mag = 10000;   //4
        else Mag = 10000;       //3
}


void _ISR _T1Interrupt(void)    //液晶表示  
{
        IFS0bits.T1IF = 0;                      //IFS0レジスタの T1IF(タイマ2の割込み検出)フラグリセット

        lcd_clear();                                            // 全消去
        sprintf(Buf,"Freq=%lu.%lu[Hz]",Freq/2,(Freq % 2)* 5);   //arguementがないと遅い  C30のバグ?
        lcd_str(Buf);
        lcd_cmd(0xC0);                                  //2行目の先頭へ
        sprintf(Buf,"*%u.%u(multiply)",Mag/2,(Mag%2)*5);        //文字列としてバッファーに収納
        lcd_str(Buf);

}


void Encode()           //エンコーダ読み込み
{
        Mag_Func();     //エンコーダ倍率
        if(PORTAbits.RA11 == 0) AswCount++;     //A相検出値が0なら AswCountをインクリメント
        else AswCount = 0;
        if(AswCount >= 8)
        {
                Asw = 0;        //AswCount = 8 の時 A相は0である。
                AswCount = 8;
        }

        if(PORTAbits.RA11 == 1)nAswCount++;     //A相検出値が1なら nAswCountをインクリメント
        else nAswCount = 0;
        if(nAswCount >= 8)
        {
                if(Asw == 0)Rising = 1;         //A相のパルスの立上り検出
                Asw = 1;        //nAswCount =  8 の時 A相は0である。
                nAswCount = 8;
        }

        if(Rising == 1) //A相パルスが立上った場合
        {
                Rising = 0;
                
        
                if(PORTDbits.RD9 == 0)
                {
                        Freq = Freq + Mag;      //C.W.の場合
                        if(Freq >= 400000)Freq = 400000;        //最大400KHz
                }
                else
                {
                        Freq = Freq - Mag;              //C.C.W.の場合
                        if(Freq <= 2) Freq = 2;
                
                
                }
        

                Duty_Count32 = 20000000/Freq;   //Duty_Count = 50カウント × 400,000Hz/Fre
                                        //2.5μsec(=1/400,000Hz) = 0.05μsec(=1/80,000,000Hz)×50カウント 

                if(Duty_Count32 <= 65535)
                {
                        Duty_Count16 = (unsigned int)Duty_Count32;
                }
                else
                {                                       //Duty0 = 0.05μsec × 65535 = 32767.5μsec = 32.7675mse
                                                        //32767.5×50 = 1638375
                        Quot = Duty_Count32/65535 ;     //Quotient 商
                        Remain = Duty_Count32 % 65535; //Remainder 余り
                }       
        

        }


                __delay32(5000);        //0.25msec(読み込み)

}


void _ISR _T2Interrupt(void)    //パルス出力
{

                if(Duty_Count32 <= 65535)       //16ビット・高周波の場合
                {
                        LATDbits.LATD0 = 0;             //Q     
                        LATDbits.LATD1 = 0;             //nQ
        
                        PR2 = Duty_Count16;     //割り込み発生までの時間設定
                                                        //50カウント → 2.5μsec(=400KHz)

                        LATDbits.LATD0 = 1;             //
                        LATDbits.LATD1 = 1;             //
                }
                else    //16ビット以上の低周波の場合
                {
                        if(Quot0 == 0)  //パルスを出す場合
                        {
                                LATDbits.LATD0 = 0;             //Q     
                                LATDbits.LATD1 = 0;             //nQ
                
                                PR2 = Remain0;  //余りを割り込み待ち時間に設定
                                Quot0 = Quot;   //現時点の商を記憶
                                Remain0 = Remain;       //現時点の余りを記憶

                                LATDbits.LATD0 = 1;             //
                                LATDbits.LATD1 = 1;             //
                        }
                        else
                        {
                                Quot0 = Quot0 - 1;      //      パルスを出さないで割り込み終了
                                PR2 = 65535;
                        }
                                

                }

        
        IFS0bits.T2IF = 0;                      //IFS0レジスタの T2IF(タイマ2の割込み検出)フラグリセット
}



int main(void)
{

        TRISA = 0xFFFF;
        ADPCFG = 0xFFFF;        //デジタルポートに設定
        TRISB = 0x003C; //
        
      
        TRISD = 0x0200;         //RD9: in
        TRISF = 0;

        LATFbits.LATF4 = 1;             //JK FF Q1 Clear Port → 1
        LATFbits.LATF5 = 1;             //JK FF Q2 Clear Port → 1

//T1タイマ         液晶表示
        OpenTimer1(
                        T1_ON   &       //タイマ1:ON
                        T1_GATE_OFF     &       //ゲート制御(信号がある時だけタイマが動作)OFF
                        T1_PS_1_256     &       //プリスケーラ 
                        T1_SYNC_EXT_OFF &       //外部同期タイマはタイマ1のみ
                        T1_SOURCE_INT,
                        23438           //300msec / 0.05μsec / 256 = 23437.5
                        );



//T2タイマ  パルス出力
        OpenTimer2(
                        T2_ON   &                       //連結タイマ2・タイマ3:ON
                        T2_GATE_OFF     &       //ゲート制御OFF
                        T2_PS_1_1       &       //プリスケーラ 1/1
                        T2_SOURCE_INT,  //クロック源: 内部クロック
                                                // 80MHz Fosc * 1/4 = 20MHz  → 0.05μsec
                        100             // 2.5μsec(= 0.05μsec × 50)  → 400KHz
                                                // 実測:2.5μsec
                        );



        lcd_init();                                                     // LCD初期化

        lcd_cmd(0b00001100);                            // カーソル:OFF  ブリンク:OFF

        lcd_clear();                                            // 全消去
        sprintf(Buf,"Pulse Generator2 %c",dummy);//arguementがないと遅い  C30のバグ?
        lcd_str(Buf);
                                                //液晶表示
        lcd_cmd(0xC0);                                  //2目表示行目の先頭へ
        sprintf(Buf,"Start !! %c",dummy);  //文字列としてバッファーに収納
        lcd_str(Buf);                                   // 開始メッセージ2行

        delay_ms(1000); 

        ConfigIntTimer1(T1_INT_PRIOR_2 & T1_INT_ON );   //割込みレベル2 連結タイマ1割込みON
        ConfigIntTimer2(T2_INT_PRIOR_5 & T2_INT_ON );   //割込みレベル5 連結タイマ2割込みON
        EnableIntT1;
        EnableIntT2;
                                                //割込み許可


        while(1)
        {
                Encode();
        }


        return 0;
}


//*************************************************************************
//インクルードファイル    1lcd_lib_C30.h
//このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、
//C30コンパイラ対応等でに変更したものです。
//*************************************************************************

#include "p30f4013.h"

#define Clock   80000000        // 単位はHzで指定

// LCDポート設定
#define lcd_port_DB7    LATBbits.LATB12 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定
#define lcd_port_DB6    LATBbits.LATB11 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定
#define lcd_port_DB5    LATBbits.LATB10 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定
#define lcd_port_DB4    LATBbits.LATB9  //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定
#define lcd_stb                 LATFbits.LATF0  //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定  
#define lcd_rs                  LATFbits.LATF1  //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定

void lcd_out(char code, char flag);
void lcd_data(char asci);
void lcd_cmd(char cmd);
void lcd_clear(void);
void lcd_init(void);
void lcd_str(char *str);


//**************************************************************************
//インクルードファイル    1lcd_lib_C30.c
//このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、
//C30コンパイラ対応等で変更したものです。
//**************************************************************************

///////////////////////////////////////////////
//  液晶表示器制御ライブラリ for C30コンパイラー
//  内蔵関数は以下
//    lcd_init()    ----- 初期化
//    lcd_cmd(cmd)  ----- コマンド出力
//    lcd_data(chr) ----- 1文字表示出力
//    lcd_clear()   ----- 全消去
//    lcd_str(str*) ----- 文字列表示 
//////////////////////////////////////////////

#include        "1lcd_lib_C30.h"
unsigned int _1usec;    // 1μsec待つに必要なウェイト回数
unsigned int _50usec;   //50μsec待つに必要なウェイト回数
unsigned long N_msec;   // 1msec待つに必要なウェイト回数



//////// データ出力サブ関数
void lcd_out(char code, char flag)
{
        if(code & 0b10000000)lcd_port_DB7 = 1;  //LCDのDB7への出力セット
        else lcd_port_DB7 = 0;
        if(code & 0b01000000)lcd_port_DB6 = 1;  //LCDのDB6への出力セット
        else lcd_port_DB6 = 0;
        if(code & 0b00100000)lcd_port_DB5 = 1;  //LCDのDB5への出力セット
        else lcd_port_DB5 = 0;
        if(code & 0b00010000)lcd_port_DB4 = 1;  //LCDのDB4への出力セット
        else lcd_port_DB4 = 0;

        if (flag == 0)
                lcd_rs = 1;                     // 表示データの場合
        else
                lcd_rs = 0;                     // コマンドデータの場合

        __delay32(_1usec);              //1μsecウェイト
                
        lcd_stb = 1;                    // strobe(E) ON (Enable)
                        
        __delay32(_1usec);              // 1μsec : strobe信号の幅

        lcd_stb = 0;                    // reset strobe
}

//////// 1文字表示関数
void lcd_data(char asci)
{
        lcd_out(asci, 0);               // 上位4ビット出力
        lcd_out(asci<<4, 0);    // 下位4ビット出力
        __delay32(_50usec);             //50μsecウェイト
}

/////// コマンド出力関数
void lcd_cmd(char cmd)
{
        lcd_out(cmd, 1);                // 上位4ビット出力
        lcd_out(cmd<<4, 1);             // 下位4ビット出力
        if((cmd & 0x03) != 0)   // clear Homeの場合
        __delay32(2*N_msec);    //      2msec待ち
        else
        __delay32(_50usec);             //50μsecウェイト    
}

/////// 全消去関数
void lcd_clear(void)
{
        lcd_cmd(0x01);                  // 初期化コマンド出力
//      __delay32(15*N_msec);   //15msecウェイト
}

/////// 文字列出力関数
void lcd_str(char* str)      
{
        while(*str)                             //文字列終端の '\0'を検出するまで
        {
                lcd_data(*str);         // 1文字表示
                str++;                          //ポインタをインクリメント                          
        }       
}


/////// 初期化関数
void lcd_init(void)
{
        _1usec =(unsigned int)( Clock / 4000000);       // 1μsecに要するウェイト回数
                                                                                                //__delay32(N) : Nが11以下の場合でも11回ウェイト
        _50usec = (unsigned int)(Clock / 4000000 * 50); //50μescに要するウェイト回数

        N_msec = (unsigned long int)(Clock / 4000);             // 1msecに要するウェイト回数
                                                                                                        // = Clock / 4000000*1000
        __delay32(20*N_msec);   //20msecウェイト
        lcd_out(0x30, 1);               // 8bit mode set
        __delay32(5*N_msec);    //5msecウェイト
        lcd_out(0x30, 1);               // 8bit mode set
        __delay32(N_msec);              //1msecウェイト
        lcd_out(0x30, 1);               // 8bit mode set
        __delay32(N_msec);              //1msecウェイト
        lcd_out(0x20, 1);               // 4bit mode set
        __delay32(N_msec);              //1msecウェイト
        lcd_cmd(0x2E);                  // DL=0 4bit mode
        lcd_cmd(0x08);                  // display off C=D=B=0
        lcd_cmd(0x0D);                  // display on C=D=1 B=0
        lcd_cmd(0x06);                  // entry I/D=1 S=0
        lcd_cmd(0x02);                  // cursor home
}





 <動作結果>

出力周波数 液晶表示 パルス波形(フリップフロップ出力) フリップフロップ入力波形
(PIC出力波形)
1.0Hz  ー
10Hz  ー
100Hz  ー
1KHzHz  ー
10KHz
 ー
100KHz  ー
200KHz



■ PIC内蔵ポートによる 液晶セグメントスタティック駆動式 16進数表示

                                                                          <HI-TECH編>


 液晶の各セグメントに印加される平均電圧は0vにする必要があります

<試作品仕様>
 ・液晶コントローラを内蔵しない液晶を スタティック駆動が可能なPICのポートを使って各液晶セグメントを直接制御する
 ・制御対象は7セグメント液晶1個とする。
 ・16進スイッチの値を 液晶に16進数で表示する。
   
 
  <試作品回路図>(→回路図のPDFファイル

  PIC16F1937、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。 
   (注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれまし



<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています





   <プログラム例>
//HI-TEC セグメント液晶スタティック制御       PIC16F1937
// Hex SW 16進表示

#include  <htc.h>

#define _XTAL_FREQ 500000       //セラミック発振子:20MHz (この設定で ディレイ関数__delay_ms()が設計の遅れ時間となる 原因不明 バグ?)

//#define _XTAL_FREQ 20000000   //セラミック発振子:20MHz     ディレイ関数用

// コンフィギュレーションの設定
__CONFIG(
                FOSC_HS &                       // EXTRC Oscillator, RC on RA7/OSC1/CLKIN
                WDTE_OFF &              // Power-up Timer Enable bit// PWRT disabled
                PWRTE_ON &              // MCLR Pin Function Select// RE3/MCLR/VPP pin function is MCLR
                MCLRE_ON &              // RE3/MCLR/VPP pin function is digital input
                CP_OFF  &               // Program memory code protection is enabled
                CPD_OFF &               // Data memory code protection is enabled
                BOREN_OFF &             // Clock Out Enable bit// CLKOUT function is disabled. I/O or oscillator function on RA6/CLKOUT
                CLKOUTEN_OFF &  // CLKOUT function is enabled on RA6/CLKOUT pin
                IESO_OFF &              // Fail Clock Monitor Enable// Fail-Safe Clock Monitor is enabled
                FCMEN_ON                // Fail-Safe Clock Monitor is disabled
                );


__CONFIG(
                WRT_OFF &       // 000h to 1FFh write protected, 200h to 1FFFh may be modified by EECON control
                PLLEN_OFF &     // 4x PLL disabled (PLLをONにしても動作時間に影響ない 原因不明 バグ?)
                STVREN_OFF &// Brown-out Reset Voltage selection// Brown-out Reset Voltage (VBOR) set to 1.9 V
//              BORV_19 &       // Brown-out Reset Voltage (VBOR) set to 2.7 V
//              DEBUG_OFF &     // Background debugger is enabled
                LVP_OFF         // HV on MCLR/VPP must not be used for programming
                );
#define b0      PORTCbits.RC3 
#define b1      PORTCbits.RC2 
#define b2      PORTCbits.RC1 
#define b3      PORTCbits.RC0 

unsigned int Seg[16] = {0b00111111,             //0
                                                0b00000110,             //1     
                                                0b01011011,             // 2
                                                0b01001111,             // 3
                                                0b01100110,             // 4
                                                0b01101101,             // 5
                                                0b01111101,             // 6
                                                0b00000111,             // 7
                                                0b01111111,             // 8
                                                0b01101111,             // 9
                                                0b01110111,             //A
                                                0b01111100,             //b
                                                0b00111001,             //C
                                                0b01011110,             //d
                                                0b01111001,             //E
                                                0b01110001};    //F

unsigned int Count;





void delay_ms(unsigned long int msec)        //1msec delay function
{
        while(msec)
        { 
                msec--; 
                __delay_ms(1);  //1msec delay
                                        
        }
}





void main()
{       


        ANSELA = 0;             //Aポートをデジタルポートに
        ANSELB = 0;             //Bポートをデジタルポートに                 
        ANSELE = 0;             //Eポートをデジタルポートに

        TRISA = 0;
        TRISB = 0;
        TRISC = 0x0F;   //b0-b3 in port


//      LCDPSレジスタ(位相レジスタ)
        LCDPSbits.WFT = 0;      //タイプAの位相が各コモンタイプ内で変化する
        LCDPSbits.BIASMD = 0;   //スタティックバイアスモードの場合は0にセット
        LCDPSbits.LCDA = 0;     //LCDドライバモジュールは非アクティブ
        LCDPSbits.WA = 0;       // LCDへの書き込みは許可されていない。
        LCDPSbits.LP3 = 0;      //LDCクロックのプリスケーラ 0000: 1/1
        LCDPSbits.LP2 = 0;      //1111: 1/16  1000: 1/9 etc
        LCDPSbits.LP1 = 0;
        LCDPSbits.LP0 = 0;      
                                                //      LCDPS  =        0x08;                   // タイプAでスタティック、1:9


        LCDSE1 = 0xFF;                  // セグメント1の全セグメント有効化
                                                        //      LCDSE0 = 0xFF;                  // 全セグメント有効化
                                                        //      LCDSE1 = 0xFF;                  // 全セグメント有効化
                                                        //      LCDSE2 = 0xFF;                  // 全セグメント有効化
        //LCDCONレジスタ(LCDドライバ有効・無効、LCDクロックソース選択)
        LCDCONbits.LCDEN = 1;   //LCDドライバー: 有効
        LCDCONbits.SLPEN = 0;   //スリープ時のLCDドライバー: 無効
        LCDCONbits.WERR = 0;    // LCDの書き込みエラーなし
        LCDCONbits.CS0 = 0;             //LCDクロックソース選択ビット
        LCDCONbits.CS1 = 0;             //同上
                                                        //00:Fosc/256 
                                                        //01:T1OSC(Timer1)   1x:LFINTOSC(31KHz) 
                                                        //LCDCON = 0x84;//0b10000100                    // スタティック、副発振有効itits
        LCDCONbits.LMUX1 = 0;   //00: スタティック制御   //スタティック・マルチプレックス制御選択
        LCDCONbits.LMUX0 = 0;   //01: 1/2マルチプレックス、  02: 1/3マルチプレックス、  03: 1/4マルチプレックス



        //LCDDATA1-3レジスタ(データレジスタ)
        LCDDATA1 = 0xFF;                // セグメント1の全セグメントオン
                                                        //LCDDATA0 = 0xFF;                      // 全セグメントオン
                                                        //LCDDATA1 = 0xFF;                      // 全セグメントオン
                                                        //LCDDATA2 = 0xFF;                      // 全セグメントオン

        //LCDRLレジスタ(リファレンス ラダー) クロック極性切り替わり時の抵抗値設定、AモードとBモードとの割合設定による省電力に係るレジスタ
        LCDRLbits.LRLAP1 = 0;   //LCDリファレンスラダーAタイムの電力制御ビット 

        LCDRLbits.LRLAP0 = 1;   //同上
                                                //01: 低電力モード      // 10: 中電力モード  11: 高電力モード

        LCDRLbits.LRLBP1 = 0;   //LCDリファレンスラダーBタイムの電力制御ビット

        LCDRLbits.LRLBP0 = 1;   //同上
                                                //01: 低電力モード      //10: 中電力モード  11: 高電力モード
        LCDRLbits.LRLAT2 = 1;   //LCDリファレンスラダーAタイムインターバル制御ビットs
        LCDRLbits.LRLAT1 = 1;   //同上
        LCDRLbits.LRLAT0 = 1;   //同上
                //111: (WFT=0が選択してあるので)タイプAの波形は、内部LCDリファレンスが、7クロック間電力モードAで9クロック間電力モードBとなる。
                //111: (WFT=1を選択している場合は)タイプBの波形は、内部LCDリファレンスが、7クロック間電力モードAで25クロック間電力モードBとなる。
                //      LCDRL    = 0x57;                        // 低電流モード

        //LCDREFレジスタ(リファレンス電圧設定、LCDバイアス電圧設定)
        LCDREFbits.LCDIRE = 1;  //1: 内部リファレンス有効 //0: 無効
        LCDREFbits.LCDIRS = 0;  //0: LCDの内部のコントラスト制御はVddを使用する。 //内部のリファレンス電圧のソース電源選択ビット
                                                //1: LCDの内部のコントラスト制御はFVRの3.072Vを使用する。
        LCDREFbits.LCDIRI = 0;  //内部リファレンスラダーアイドルイネーブルビット
                                                //0: LCDのFVRバッファーは、LCDリファレンスのパワーモードを無視する。
        LCDREFbits.VLCD3PE = 0; //VCLD3ピンは接続されない //外部LCDバイアス電圧を使用する場合に接続する
        LCDREFbits.VLCD2PE = 0; //VCLD2ピンは接続されない
        LCDREFbits.VLCD1PE = 0; //VCLD1ピンは接続されない

                                                //      LCDREF = 0x80;          //0b10000000            // 内蔵バイアス、VLCD入力なし

        //LCDCSTレジスタ(コントラスト設定)
        LCDCSTbits.LCDCST2 = 0; //LCDのコントラスト制御ビット
        LCDCSTbits.LCDCST1 = 1; //同上
        LCDCSTbits.LCDCST0 = 1; //同上
                                                //011 ラダー抵抗は最大抵抗の3/7、コントラストは中程度
                                                //000 ラダー抵抗は最小(ラダー抵抗は短絡)、最大コントラスト
                                                //111 ラダー抵抗は最大、最小コントラスト

                                        //LCDCST = 0x03; //0b00000011                   // 中コントラスト




        //T1CON レジスタ(Timer1 Control Resister)
        TMR1CS1 = 0;    //Timer1 clock source: Fosc/4 //Timer1 Clock Source Select bits
        TMR1CS0 = 0;    //TMR1CS<1:0> = 00 → Fosc/4 // 01 → Fosc
        T1CKPS1 = 0;    //プリスケーラ 1/1 //Prescale Select bits
        T1CKPS0 = 0;    //T1CKPS<1:0> = 00 → 1/1 //10→1/4 01→1/2 00→1/1
        T1OSCEN = 0;    //LP Oscillator Enble Control bit
        nT1SYNC = 0;    //Timer1 External Clock Input Synchronization Control bit
        TMR1ON = 1;             //Enable Timer1 //Timer1 On bit

        //T1GCON レジスタ(Timer1 Gate Control Resister)     // ゲート機能なし
        TMR1GE = 0;             //Timer1 Gate Enable bit
        T1GPOL = 0;             //Timer1 Gate Polarity bit
        T1GTM = 0;              //Timer1 Gate Toggle Mode bit
        T1GSPM = 0;             //Timer1 Gate Single Pulse Mode bit
        T1GGO = 0;              //Timer1 Gate Single-Pulse Acquisition Status bit
        T1GVAL = 0;             //Timer1 Gate current State bit
        T1GSS1 = 0;             //Timer1 Gate Source Select bits
        T1GSS0 = 0;




        TMR1H = 0xFB;   //                      
        TMR1L = 0x1E;   //




        __delay_ms(1);



        while(1)
        {
                if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 1)) LCDDATA1 = Seg[0];
                else if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 0)) LCDDATA1 = Seg[1];
                else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 1)) LCDDATA1 = Seg[2];
                else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 0)) LCDDATA1 = Seg[3];
                else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 1)) LCDDATA1 = Seg[4];
                else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 0)) LCDDATA1 = Seg[5];
                else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 1)) LCDDATA1 = Seg[6];
                else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 0)) LCDDATA1 = Seg[7];
                else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 1)) LCDDATA1 = Seg[8];
                else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 0)) LCDDATA1 = Seg[9];
                else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 1)) LCDDATA1 = Seg[10];
                else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 0)) LCDDATA1 = Seg[11];
                else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 1)) LCDDATA1 = Seg[12];
                else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 0)) LCDDATA1 = Seg[13];
                else if((b3 == 0) && (b2 == 0) && (b1 == 0) && (b0 == 1)) LCDDATA1 = Seg[14];
                else  LCDDATA1 = Seg[15];

        }

}

<動作結果>
  HEX スイッチをFに回した時の写真です。


液晶表示
電圧波形
表示セグメント
セグメント印加電圧
上段: 4A(2v/div)
下段: COM(2v/div)
非表示セグメント
上段: 4B(2v/div)
下段: COM(2v/div)
25msec/div
デジタルオシロスコープ
ATTEN製(中国) ADS1102CA





■ PIC内蔵ポートによる 液晶セグメントスタティック駆動式 カウンタ  
                                        <HI-TECH編>

  液晶の各セグメントに印加される平均電圧は0vにする必要があります
<試作品仕様>
 ・液晶コントローラを内蔵しない液晶を スタティック駆動が可能なPICのポートを使って各液晶セグメントを直接制御する
 ・制御対象は7セグメント液晶1個とする。
 ・周期1秒の16進カウンタを製作のこと。 また、 Fの次は 0に戻ること
   すなわち 0 → 1 → 2 → 3 ……… C → d → E → F → 0 → 1
 
  <試作品回路図>(→回路図のPDFファイル

  PIC16F1937、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。 
   (注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれました。

<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています



          

<プログラム例>
//HI-TEC セグメント液晶スタティック制御       PIC16F1937
// 1桁 16進カウンタ

#include  <htc.h>

#define _XTAL_FREQ 500000       //セラミック発振子:20MHz (この設定で ディレイ関数__delay_ms()が設計の遅れ時間となる 原因不明 バグ?)

//#define _XTAL_FREQ 20000000   //セラミック発振子:20MHz     ディレイ関数用

// コンフィギュレーションの設定
__CONFIG(
                FOSC_HS &                       // EXTRC Oscillator, RC on RA7/OSC1/CLKIN
                WDTE_OFF &              // Power-up Timer Enable bit// PWRT disabled
                PWRTE_ON &              // MCLR Pin Function Select// RE3/MCLR/VPP pin function is MCLR
                MCLRE_ON &              // RE3/MCLR/VPP pin function is digital input
                CP_OFF  &               // Program memory code protection is enabled
                CPD_OFF &               // Data memory code protection is enabled
                BOREN_OFF &             // Clock Out Enable bit// CLKOUT function is disabled. I/O or oscillator function on RA6/CLKOUT
                CLKOUTEN_OFF &  // CLKOUT function is enabled on RA6/CLKOUT pin
                IESO_OFF &              // Fail Clock Monitor Enable// Fail-Safe Clock Monitor is enabled
                FCMEN_ON                // Fail-Safe Clock Monitor is disabled
                );


__CONFIG(
                WRT_OFF &       // 000h to 1FFh write protected, 200h to 1FFFh may be modified by EECON control
                PLLEN_OFF &     // 4x PLL disabled (PLLをONにしても動作時間に影響ない 原因不明 バグ?)
                STVREN_OFF &// Brown-out Reset Voltage selection// Brown-out Reset Voltage (VBOR) set to 1.9 V
//              BORV_19 &       // Brown-out Reset Voltage (VBOR) set to 2.7 V
//              DEBUG_OFF &     // Background debugger is enabled
                LVP_OFF         // HV on MCLR/VPP must not be used for programming
                );


unsigned int Seg[16] = {0b00111111,             //0
                                                0b00000110,             //1     
                                                0b01011011,             // 2
                                                0b01001111,             // 3
                                                0b01100110,             // 4
                                                0b01101101,             // 5
                                                0b01111101,             // 6
                                                0b00000111,             // 7
                                                0b01111111,             // 8
                                                0b01101111,             // 9
                                                0b01110111,             //A
                                                0b01111100,             //b
                                                0b00111001,             //C
                                                0b01011110,             //d
                                                0b01111001,             //E
                                                0b01110001};    //F

unsigned int Count;
int ix ;




void delay_ms(unsigned long int msec)        //1msec delay function
{
        while(msec)
        { 
                msec--; 
                __delay_ms(1);  //1msec delay
                                        
        }
}




void interrupt isr(void)        //10msec毎の割り込み
{
        TMR1IF = 0;     //フラグクリア

//アップカウンタの値設定
//Clock: 20MHz/4 → 5MHz 0.2μsec
// 10msec毎の割り込みを行う
//プリスケーラ 1/1 //Prescale Select bits
// <計算>
//    (65536 -N)*0.2*1 = 10000 [μsec]
//     N = 65536 - 50000 = 15536
//     15536 = 0x3C6B 実測割り込みインターバル = 400msec(原因不明 バグ?)
//    対応:  10000μsec * 1/40  = 250μsec
//    (56636 -N)*0.2*1 = 250 [μsec] 
//    N = 65536 - 1250 = 642486 = 0xFB1E (実測割り込みインターバル: 10msec)

        TMR1H = 0xFB;   //                      
        TMR1L = 0x1E;   //

        Count++;
        if(Count >= 100)
        {
                Count = 0;
                LCDDATA1 = Seg[ix];     //液晶セグメント表示
                ix++;
                if(ix >=16)ix = 0;
        }


}


void main()
{       


        ANSELA = 0;             //Aポートをデジタルポートに
        ANSELB = 0;             //Bポートをデジタルポートに                 
        ANSELE = 0;             //Eポートをデジタルポートに

        TRISA = 0;
        TRISB = 0;
        TRISC = 0;


//      LCDPSレジスタ(位相レジスタ)
        LCDPSbits.WFT = 0;      //タイプAの位相が各コモンタイプ内で変化する
        LCDPSbits.BIASMD = 0;   //スタティックバイアスモードの場合は0にセット
        LCDPSbits.LCDA = 0;     //LCDドライバモジュールは非アクティブ
        LCDPSbits.WA = 0;       // LCDへの書き込みは許可されていない。
        LCDPSbits.LP3 = 0;      //LDCクロックのプリスケーラ 0000: 1/1
        LCDPSbits.LP2 = 0;      //1111: 1/16  1000: 1/9 etc
        LCDPSbits.LP1 = 0;
        LCDPSbits.LP0 = 0;      
                                                //      LCDPS  =        0x08;                   // タイプAでスタティック、1:9


        LCDSE1 = 0xFF;                  // セグメント1の全セグメント有効化
                                                        //      LCDSE0 = 0xFF;                  // 全セグメント有効化
                                                        //      LCDSE1 = 0xFF;                  // 全セグメント有効化
                                                        //      LCDSE2 = 0xFF;                  // 全セグメント有効化
        //LCDCONレジスタ(LCDドライバ有効・無効、LCDクロックソース選択)
        LCDCONbits.LCDEN = 1;   //LCDドライバー: 有効
        LCDCONbits.SLPEN = 0;   //スリープ時のLCDドライバー: 無効
        LCDCONbits.WERR = 0;    // LCDの書き込みエラーなし
        LCDCONbits.CS0 = 0;             //LCDクロックソース選択ビット
        LCDCONbits.CS1 = 0;             //同上
                                                        //00:Fosc/256 
                                                        //01:T1OSC(Timer1)   1x:LFINTOSC(31KHz) 
                                                        //LCDCON = 0x84;//0b10000100                    // スタティック、副発振有効itits
        LCDCONbits.LMUX1 = 0;   //00: スタティック制御   //スタティック・マルチプレックス制御選択
        LCDCONbits.LMUX0 = 0;   //01: 1/2マルチプレックス、  02: 1/3マルチプレックス、  03: 1/4マルチプレックス



        //LCDDATA1-3レジスタ(データレジスタ)
        LCDDATA1 = 0xFF;                // セグメント1の全セグメントオン
                                                        //LCDDATA0 = 0xFF;                      // 全セグメントオン
                                                        //LCDDATA1 = 0xFF;                      // 全セグメントオン
                                                        //LCDDATA2 = 0xFF;                      // 全セグメントオン

        //LCDRLレジスタ(リファレンス ラダー) クロック極性切り替わり時の抵抗値設定、AモードとBモードとの割合設定による省電力に係るレジスタ
        LCDRLbits.LRLAP1 = 0;   //LCDリファレンスラダーAタイムの電力制御ビット 

        LCDRLbits.LRLAP0 = 1;   //同上
                                                //01: 低電力モード      // 10: 中電力モード  11: 高電力モード

        LCDRLbits.LRLBP1 = 0;   //LCDリファレンスラダーBタイムの電力制御ビット

        LCDRLbits.LRLBP0 = 1;   //同上
                                                //01: 低電力モード      //10: 中電力モード  11: 高電力モード
        LCDRLbits.LRLAT2 = 1;   //LCDリファレンスラダーAタイムインターバル制御ビットs
        LCDRLbits.LRLAT1 = 1;   //同上
        LCDRLbits.LRLAT0 = 1;   //同上
                //111: (WFT=0が選択してあるので)タイプAの波形は、内部LCDリファレンスが、7クロック間電力モードAで9クロック間電力モードBとなる。
                //111: (WFT=1を選択している場合は)タイプBの波形は、内部LCDリファレンスが、7クロック間電力モードAで25クロック間電力モードBとなる。
                //      LCDRL    = 0x57;                        // 低電流モード

        //LCDREFレジスタ(リファレンス電圧設定、LCDバイアス電圧設定)
        LCDREFbits.LCDIRE = 1;  //1: 内部リファレンス有効 //0: 無効
        LCDREFbits.LCDIRS = 0;  //0: LCDの内部のコントラスト制御はVddを使用する。 //内部のリファレンス電圧のソース電源選択ビット
                                                //1: LCDの内部のコントラスト制御はFVRの3.072Vを使用する。
        LCDREFbits.LCDIRI = 0;  //内部リファレンスラダーアイドルイネーブルビット
                                                //0: LCDのFVRバッファーは、LCDリファレンスのパワーモードを無視する。
        LCDREFbits.VLCD3PE = 0; //VCLD3ピンは接続されない //外部LCDバイアス電圧を使用する場合に接続する
        LCDREFbits.VLCD2PE = 0; //VCLD2ピンは接続されない
        LCDREFbits.VLCD1PE = 0; //VCLD1ピンは接続されない

                                                //      LCDREF = 0x80;          //0b10000000            // 内蔵バイアス、VLCD入力なし

        //LCDCSTレジスタ(コントラスト設定)
        LCDCSTbits.LCDCST2 = 0; //LCDのコントラスト制御ビット
        LCDCSTbits.LCDCST1 = 1; //同上
        LCDCSTbits.LCDCST0 = 1; //同上
                                                //011 ラダー抵抗は最大抵抗の3/7、コントラストは中程度
                                                //000 ラダー抵抗は最小(ラダー抵抗は短絡)、最大コントラスト
                                                //111 ラダー抵抗は最大、最小コントラスト

                                        //LCDCST = 0x03; //0b00000011                   // 中コントラスト




        //T1CON レジスタ(Timer1 Control Resister)
        TMR1CS1 = 0;    //Timer1 clock source: Fosc/4 //Timer1 Clock Source Select bits
        TMR1CS0 = 0;    //TMR1CS<1:0> = 00 → Fosc/4 // 01 → Fosc
        T1CKPS1 = 0;    //プリスケーラ 1/1 //Prescale Select bits
        T1CKPS0 = 0;    //T1CKPS<1:0> = 00 → 1/1 //10→1/4 01→1/2 00→1/1
        T1OSCEN = 0;    //LP Oscillator Enble Control bit
        nT1SYNC = 0;    //Timer1 External Clock Input Synchronization Control bit
        TMR1ON = 1;             //Enable Timer1 //Timer1 On bit

        //T1GCON レジスタ(Timer1 Gate Control Resister)     // ゲート機能なし
        TMR1GE = 0;             //Timer1 Gate Enable bit
        T1GPOL = 0;             //Timer1 Gate Polarity bit
        T1GTM = 0;              //Timer1 Gate Toggle Mode bit
        T1GSPM = 0;             //Timer1 Gate Single Pulse Mode bit
        T1GGO = 0;              //Timer1 Gate Single-Pulse Acquisition Status bit
        T1GVAL = 0;             //Timer1 Gate current State bit
        T1GSS1 = 0;             //Timer1 Gate Source Select bits
        T1GSS0 = 0;




        TMR1H = 0xFB;   //                      
        TMR1L = 0x1E;   //



        TMR1IE = 1;                             // タイマ1割り込み許可
        PEIE = 1;                               // 周辺割り込み許可許可
        GIE = 1;                                // グローバル割り込み許可



        __delay_ms(1);



        while(1)
        {
/*
                for(ix = 0; ix<16; ix++)
                {
                        LCDDATA1 = Seg[ix];
                        delay_ms(1000);
                }

*/
        }


}

<動作結果>
 6がカウントされ 液晶に表示された場合の写真です。




■ 外付けXORによる 液晶セグメント スタティック駆動式 16進数表示


液晶の各セグメントに印加される平均電圧は0vにする必要があります。

<試作品仕様>
 ・液晶コントローラを内蔵しない液晶を スタティック駆動により各液晶セグメントを直接制御する
 ・PICの出力I/Oは スタティック液晶駆動用ではない一般のI/Oを用い、 外付け回路により液晶印可電圧平均値を0Vにすること。
 ・液晶の駆動周波数は302Hzとする。
 ・制御対象は7セグメント液晶1個とする。
 ・16進スイッチの値を 液晶に16進数で表示する。
   
 
  <試作品回路図>(→回路図のPDFファイル

  PIC16F1937、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。 
   (注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれました。





<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています




   <プログラム例>
// XORを使用した 液晶セグメントスタティック駆動制御
//               HeXスイッチの値表示
//                                     PIC18F452, C18コンパイラ

#include <p18f452.h>
#include <delays.h>

#pragma config OSC = HS      // f = 20MHz
#pragma config WDT = OFF
#pragma config LVP = OFF

//入力ポート 設定
#define b0      PORTDbits.RD0 
#define b1      PORTCbits.RC3 
#define b2      PORTCbits.RC1 
#define b3      PORTCbits.RC0 

//出力ポート 設定
#define A       PORTCbits.RC7
#define B       PORTCbits.RC6
#define C       PORTCbits.RC5
#define D       PORTCbits.RC4
#define E       PORTAbits.RA0
#define F       PORTBbits.RB7
#define G       PORTBbits.RB6


void Func_0(){G = 0; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;}         // 0 を表示
void Func_1(){G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 0;}         // 1 を表示
void Func_2(){G = 1; F = 0; E = 1; D = 1; C = 0; B = 1; A = 1;}         // 2 を表示
void Func_3(){G = 1; F = 0; E = 0; D = 1; C = 1; B = 1; A = 1;}         //3 を表示
void Func_4(){G = 1; F = 1; E = 0; D = 0; C = 1; B = 1; A = 0;}         //4 を表示
void Func_5(){G = 1; F = 1; E = 0; D = 1; C = 1; B = 0; A = 1;}         //5 を表示
void Func_6(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 1;}         //6 を表示
void Func_7(){G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 1;}         //7 を表示
void Func_8(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;}         //8 を表示
void Func_9(){G = 1; F = 1; E = 0; D = 1; C = 1; B = 1; A = 1;}         //9 を表示
void Func_A(){G = 1; F = 1; E = 1; D = 0; C = 1; B = 1; A = 1;}         //A を表示
void Func_b(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 0;}         //b を表示
void Func_C(){G = 0; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;}         //C を表示
void Func_d(){G = 1; F = 0; E = 1; D = 1; C = 1; B = 1; A = 0;}         //d を表示
void Func_E(){G = 1; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;}         //E を表示
void Func_F(){G = 1; F = 1; E = 1; D = 0; C = 0; B = 0; A = 1;}         //F を表示
  



void delay_ms (long int cycle)  // CCSコンパイラと同じ delay_ms(long int) 関数を設計
{
        long int i = 0;
        for (i = 0; i < cycle*5; i++)Delay1KTCYx(1);     // 0.05μsec × 4 × 1000 = 0.2msec
}

void main (void)
{
        TRISA = 0;
        TRISB = 0;
        TRISC = 0b00001011;
        TRISD = 0b00000001;

        // CCP: PWMモード 1.2KHz duty=1/2
        T2CONbits.T2CKPS1 = 1;  // prescale: 1/16
        CCP1CON = 0b00111111;   //bit5,4 PWM duty cycle //bit3,2 =11 → PWM mode 
        PR2 = 0xFF;                             // PWM period = (PR2 + 1)*4*Tosc*(TMR2prescale value)
        TMR2 = 0x7F;                    // = (256 + 1) * 4 * 0.05μsec * 16
        T2CONbits.TMR2ON = 1;   // = 822.4μsec = 0.8224msec(1.215KHz)(実測:1.22KHz) → 液晶クロック=1.21KHz / 4 = 302Hz
        CCPR1L = 0x7F;                  // PWM duty cycle = CCPR1L:CCPCON<5:4> * Tosc * (TMR2prescale value)
                                                        // = 0b01111111 11(511) * 0.05 * 256
                                                        //                                                      


        while (1)
    {

                if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 1))Func_0();
                else if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 0)) Func_1();
                else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 1)) Func_2();
                else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 0)) Func_3();
                else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 1)) Func_4();
                else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 0)) Func_5();
                else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 1)) Func_6();
                else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 0)) Func_7();
                else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 1)) Func_8();
                else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 0)) Func_9();
                else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 1)) Func_A();
                else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 0)) Func_b();
                else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 1)) Func_C();
                else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 0)) Func_d();
                else if((b3 == 0) && (b2 == 0) && (b1 == 0) && (b0 == 1)) Func_E();
                else  Func_F();


/*

                PORTDbits.RD1 = 0;     // RD1 LED ON
                delay_ms(1000);   //1000msec delay
                PORTDbits.RD1 = 1;     // BポートのLED OFF
                delay_ms(1000);   // 1000msec delay
*/

    }
}

<動作結果>

 HEXスイッチの7を選択した時の表示の写真です。

液晶表示
電圧波形
表示液晶セグメント
上段: 4A (2v/div)
下段: COM (2v/div)
非表示液晶セグメント
上段: 4G(2v/div)
下段: COM(2v/div)
1msec/div
デジタルオシロスコープ
ATTEN製(中国) ADS1102CA





■ 外付けXORによる 液晶セグメント スタティック駆動式 カウンタ


液晶の各セグメントに印加される平均電圧は0vにする必要があります。

<試作品仕様>
 ・液晶コントローラを内蔵しない液晶を スタティック駆動により各液晶セグメントを直接制御する
 ・PICの出力I/Oは スタティック液晶駆動用ではない一般のI/Oを用い、 外付け回路により液晶印可電圧平均値を0Vにすること。
 ・液晶の駆動周波数は302Hzとする。
 ・制御対象は7セグメント液晶1個とする。
 ・周期1秒の16進カウンタを製作のこと。 また、 Fの次は 0に戻ること
   すなわち 0 → 1 → 2 → 3 ……… C → d → E → F → 0 → 1
 
  <試作品回路図>(→回路図のPDFファイル

  PIC16F1937、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。 
   (注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれました。





<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています

   <プログラム例>
// XORを使用した 液晶セグメントスタティック駆動制御
//               カウンタ
//                                     PIC18F452, C18コンパイラ

#include <p18f452.h>
#include <delays.h>
#include <timers.h>

#pragma config OSC = HS      // f = 20MHz
#pragma config WDT = OFF
#pragma config LVP = OFF



//出力ポート 設定
#define A       PORTCbits.RC7
#define B       PORTCbits.RC6
#define C       PORTCbits.RC5
#define D       PORTCbits.RC4
#define E       PORTAbits.RA0
#define F       PORTBbits.RB7
#define G       PORTBbits.RB6


unsigned long int       Count1 = 0;
unsigned long int       Count2 = 0;
int LED = 0;



void Func_0(){G = 0; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;}         // 0 を表示
void Func_1(){G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 0;}         // 1 を表示
void Func_2(){G = 1; F = 0; E = 1; D = 1; C = 0; B = 1; A = 1;}         // 2 を表示
void Func_3(){G = 1; F = 0; E = 0; D = 1; C = 1; B = 1; A = 1;}         //3 を表示
void Func_4(){G = 1; F = 1; E = 0; D = 0; C = 1; B = 1; A = 0;}         //4 を表示
void Func_5(){G = 1; F = 1; E = 0; D = 1; C = 1; B = 0; A = 1;}         //5 を表示
void Func_6(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 1;}         //6 を表示
void Func_7(){G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 1;}         //7 を表示
void Func_8(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;}         //8 を表示
void Func_9(){G = 1; F = 1; E = 0; D = 1; C = 1; B = 1; A = 1;}         //9 を表示
void Func_A(){G = 1; F = 1; E = 1; D = 0; C = 1; B = 1; A = 1;}         //A を表示
void Func_b(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 0;}         //b を表示
void Func_C(){G = 0; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;}         //C を表示
void Func_d(){G = 1; F = 0; E = 1; D = 1; C = 1; B = 1; A = 0;}         //d を表示
void Func_E(){G = 1; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;}         //E を表示
void Func_F(){G = 1; F = 1; E = 1; D = 0; C = 0; B = 0; A = 1;}         //F を表示
  



void delay_ms (long int cycle)  // CCSコンパイラと同じ delay_ms(long int) 関数を設計
{
        long int i = 0;
        for (i = 0; i < cycle*5; i++)Delay1KTCYx(1);     // 0.05μsec × 4 × 1000 = 0.2msec
}


#pragma interrupt my_Func               // 10msec タイマ1 インターバル割り込み

#pragma code isrcode = 0x08
void isr_direct(void)
{ _asm goto my_Func _endasm }
#pragma code

void my_Func(void)
{
        PIR1bits.TMR1IF = 0;    // タイマ1割り込みフラグをクリアする
         WriteTimer1(59286);    // 0.05μsec × 4 × 8 × 6250 = 10000μsec = 10msec (at システムクロック20MHz)
                                                        // 256×256 - 6250 = 59286
                                                        // タイマ0:16bitアップカウントタイマ → オーバーフローで割込み発生
        Count1++;
        if(Count1 >= 100)               //1秒毎に
        {
                Count1 = 0;
        
                if(Count2 == 0)Func_0();
                else if(Count2 == 1) Func_1();
                else if(Count2 == 2) Func_2();
                else if(Count2 == 3) Func_3();
                else if(Count2 == 4) Func_4();
                else if(Count2 == 5) Func_5();
                else if(Count2 == 6) Func_6();
                else if(Count2 == 7) Func_7();
                else if(Count2 == 8) Func_8();
                else if(Count2 == 9) Func_9();
                else if(Count2 == 10) Func_A();
                else if(Count2 == 11) Func_b();
                else if(Count2 == 12) Func_C();
                else if(Count2 == 13) Func_d();
                else if(Count2 == 14) Func_E();
                else  Func_F();

                Count2++;
                if(Count2 >= 16)Count2 = 0;

                if(LED == 1)
                {
                        PORTDbits.RD1 = 0;     // RD1 LED ON
                        LED = 0;
                }
                else
                {
                        PORTDbits.RD1 = 1;     // BポートのLED OFF
                        LED = 1;
                }

        }
}

void main (void)
{
        TRISA = 0;
        TRISB = 0;
        TRISC = 0b00001011;
        TRISD = 0b00000001;

        // CCP: PWMモード 1.2KHz duty=1/2
        T2CONbits.T2CKPS1 = 1;  // prescale: 1/16
        CCP1CON = 0b00111111;   //bit5,4 PWM duty cycle //bit3,2 =11 → PWM mode 
        PR2 = 0xFF;                             // PWM period = (PR2 + 1)*4*Tosc*(TMR2prescale value)
        TMR2 = 0x7F;                    // = (256 + 1) * 4 * 0.05μsec * 16
        T2CONbits.TMR2ON = 1;   // = 822.4μsec = 0.8224msec(1.215KHz)(実測:1.22KHz) → 液晶クロック=1.21KHz / 4 = 302Hz
        CCPR1L = 0x7F;                  // PWM duty cycle = CCPR1L:CCPCON<5:4> * Tosc * (TMR2prescale value)
                                                        // = 0b01111111 11(511) * 0.05 * 256
                                                        //      

        //タイマ0の設定 
        OpenTimer1
        (
                TIMER_INT_ON &  //割込み:ON
                T1_16BIT_RW &   //16 bit モードに設定  vs  8bit モード( T0_8BIT )
                T1_SOURCE_INT & //内部クロック使用
                T1_PS_1_8 &             //8ビットプリスケーラ  1/8 vs 1/1 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256 
                T1_OSC1EN_OFF
        );
                                                
        WriteTimer1(59286);

        RCONbits.IPEN = 0;              //割込み優先順位制御:OFF (RCON レジスタのIPENビット = 0)
        PIE1bits.TMR1IE = 1;               //タイマ1割込み許可
        INTCONbits.PEIE =1;             //周辺割込み許可 
                                                                //INTCONレジスタの b6ビット : 低位割込み許可/禁止(割り込み優先順位制御     有りの場合)                                  
        INTCONbits.GIE = 1;             //全割込み許可
                                                        //INTCONレジスタの b7ビット : 高位割込み許可/禁止(割り込み優先順位制御  有りの場合)


        while (1)
    {
    }

}


<動作結果>

 カウント値が9の時の写真です。



■ PIC内蔵ポートによる 液晶セグメントスタティック駆動式 16進数表示

                                                                          <C18編>


 液晶の各セグメントに印加される平均電圧は0vにする必要があります

<試作品仕様>
 ・液晶コントローラを内蔵しない液晶を スタティック駆動が可能なPICのポートを使って各液晶セグメントを直接制御する
 ・制御対象は7セグメント液晶1個とする。
 ・16進スイッチの値を 液晶に16進数で表示する。
   
 
  <試作品回路図>(→回路図のPDFファイル

  PIC18F85J90、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。 
  PIM内部の接続は何故かトリッキーな接続となっているので設計には十分気おつけることが必要です。
   (注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれまし





<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています


   <プログラム例>
/*
HexSwの値を LCDに表示                 
*/

#include <p18f85J90.h>

#include <stdio.h>
#include <delays.h>


#pragma config FOSC = HS // システムクロック=20MHz 
#pragma config XINST = OFF
#pragma config  WDTEN = OFF     //ウォッチドックタイマ OFF



//入力ポート 設定
#define b0      PORTHbits.RH0 
#define b1      PORTGbits.RG2
#define b2      PORTCbits.RC1
#define b3      PORTGbits.RG3 



void Func_0(){LCDDATA0 = 0b0111111;}    // 0 を表示        //G = 0; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;      
void Func_1(){LCDDATA0 = 0b00000110;}   // 1 を表示        //G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 0;
void Func_2(){LCDDATA0 = 0b01011011;}   // 2 を表示  //G = 1; F = 0; E = 1; D = 1; C = 0; B = 1; A = 1;
void Func_3(){LCDDATA0 = 0b01001111;}   //3 を表示   //G = 1; F = 0; E = 0; D = 1; C = 1; B = 1; A = 1;
void Func_4(){LCDDATA0 = 0b01100110;}   //4 を表示 //G = 1; F = 1; E = 0; D = 0; C = 1; B = 1; A = 0;
void Func_5(){LCDDATA0 = 0b01101101;}   //5 を表示 //G = 1; F = 1; E = 0; D = 1; C = 1; B = 0; A = 1;
void Func_6(){LCDDATA0 = 0b01111101;}   //6 を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 1;
void Func_7(){LCDDATA0 = 0b00000111;}   //7 を表示 //G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 1;
void Func_8(){LCDDATA0 = 0b01111111;}   //8 を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;
void Func_9(){LCDDATA0 = 0b01101111;}   //9 を表示 //G = 1; F = 1; E = 0; D = 1; C = 1; B = 1; A = 1;
void Func_A(){LCDDATA0 = 0b01110111;}   //A を表示 //G = 1; F = 1; E = 1; D = 0; C = 1; B = 1; A = 1;
void Func_b(){LCDDATA0 = 0b01111100;}   //b を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 0;
void Func_C(){LCDDATA0 = 0b00111001;}   //C を表示 //G = 0; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;
void Func_d(){LCDDATA0 = 0b01011110;}   //d を表示 //G = 1; F = 0; E = 1; D = 1; C = 1; B = 1; A = 0;
void Func_E(){LCDDATA0 = 0b01111001;}   //E を表示 //G = 1; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;
void Func_F(){LCDDATA0 = 0b01110001;}   //F を表示 //G = 1; F = 1; E = 1; D = 0; C = 0; B = 0; A = 1;







void main (void)
{
        
        TRISCbits.RC1 = 1;      // RC1: in //HexSw
        TRISG = 0xFF;   //G port: in    //HexSw
        TRISD = 0x00;   //D port: out   //Segment Data
        TRISEbits.RE3 = 0;      //COM0: out
        TRISHbits.RH0 = 1;      //HexSw b0
        TRISHbits.RH2 = 0;      //LED free run


// LCDCON (LCD CONTROL)レジスタ

        LCDCONbits.SLPEN = 0;   //Sleep時のLCDドライバーモジュール イネーブル
        LCDCONbits.WERR = 0;    //No LCD Write Erro //LCD Write Failed Error bit
        LCDCONbits.CS1   = 0; //00 Fosc/4  1x INTRC(31KHz)   00 Sys Clock, 01 TMR1 Clk
        LCDCONbits.CS0   = 0; // 
        LCDCONbits.LMUX1 = 0;   //00 Static(COM0)スタティック制御  //Commons Select bis 
        LCDCONbits.LMUX0 = 0;

// LCDPS(LCD PHASE) レジスタ
        LCDPSbits.WFT     = 0;  //0 - TypeA(Phase changes whithin each common type)
        LCDPSbits.BIASMD  = 0;  //Bias Mode Select bit(スタティックモードでは0にセットのこと) 

        LCDPSbits.LCDA = 0;     //LCDドライバモジュールは非アクティブ
        LCDPSbits.WA = 0;       // LCDへの書き込みは許可されていない。

        LCDPSbits.LP3 = 0;              //0100LP <3:0> LCDクロックのプリスケーラ 1/5
        LCDPSbits.LP2 = 1;      
        LCDPSbits.LP1 = 0;
        LCDPSbits.LP0 = 0;


// LCDSEx (LCD SEGMENT ENABLE)レジスタ
// 1: セグメント機能モード  0: I/Oモード
        LCDSE0 = 0xFF;  //対応ポート: SEG0-SEG7 //セグメント機能モード 
        LCDSE1 = 0x00;  //対応ポート: SEG8-SEG15//デジタルI/Oモード 
        LCDSE2 = 0x00;  //対応ポート: SEG16-SE23//デジタルI/Oモード  
        LCDSE3 = 0x00;  //対応ポート: SEG24-SEG31//デジタルI/Oモード  
        LCDSE4 = 0x00;  //対応ポート: SEG32-SEG39 //デジタルI/Oモード  
        LCDSE5 = 0x00;  //対応ポート: SEG40-SEG47 //デジタルI/Oモード  


 // LCDREG(VOLTAGE REGULATOR CONTROL)レジスタ
        LCDREGbits.CPEN   = 0;  //LCDチャージポンプOFF// LCD charge Pump Enable bit
        LCDREGbits.CKSEL1 = 0;  //Regulator Clock Source Select bit //LCD レギュレータ ディセーブル //
        LCDREGbits.CKSEL0 = 0;  //

        LCDCONbits.LCDEN = 1;   //LCDドライバーモジュール イネーブル   

         while (1)
    {
                if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 1))Func_0();
                else if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 0)) Func_1();
                else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 1)) Func_2();
                else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 0)) Func_3();
                else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 1)) Func_4();
                else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 0)) Func_5();
                else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 1)) Func_6();
                else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 0)) Func_7();
                else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 1)) Func_8();
                else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 0)) Func_9();
                else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 1)) Func_A();
                else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 0)) Func_b();
                else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 1)) Func_C();
                else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 0)) Func_d();
                else if((b3 == 0) && (b2 == 0) && (b1 == 0) && (b0 == 1)) Func_E();
                else  Func_F();


    }


}


 

<動作結果>
 HEXスイッチを5に設定した場合の液晶表示の写真です。




■ PIC内蔵ポートによる 液晶セグメントスタティック駆動式 カウンタ  
                                        <C18編>

 液晶の各セグメントに印加される平均電圧は0vにする必要があります
<試作品仕様>
 ・液晶コントローラを内蔵しない液晶を スタティック駆動が可能なPICのポートを使って各液晶セグメントを直接制御する
 ・制御対象は7セグメント液晶1個とする。
 ・周期1秒の16進カウンタを製作のこと。 また、 Fの次は 0に戻ること
   すなわち 0 → 1 → 2 → 3 ……… C → d → E → F → 0 → 1
 
  <試作品回路図>(→回路図のPDFファイル

  PIC18F85J90、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。 
   (注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれました。


<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています


   <プログラム例>
/*
1秒毎の 16進Counter値を表示             
*/

#include <p18f85J90.h>

#include <stdio.h>
#include <delays.h>
#include <timers.h>


#pragma config FOSC = HS // システムクロック=20MHz 
#pragma config XINST = OFF
#pragma config  WDTEN = OFF     //ウォッチドックタイマ OFF


unsigned long int Count1 = 0;
unsigned long int Count2 = 0;
int LED = 0;







void Func_0(){LCDDATA0 = 0b0111111;}    // 0 を表示        //G = 0; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;      
void Func_1(){LCDDATA0 = 0b00000110;}   // 1 を表示        //G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 0;
void Func_2(){LCDDATA0 = 0b01011011;}   // 2 を表示  //G = 1; F = 0; E = 1; D = 1; C = 0; B = 1; A = 1;
void Func_3(){LCDDATA0 = 0b01001111;}   //3 を表示   //G = 1; F = 0; E = 0; D = 1; C = 1; B = 1; A = 1;
void Func_4(){LCDDATA0 = 0b01100110;}   //4 を表示 //G = 1; F = 1; E = 0; D = 0; C = 1; B = 1; A = 0;
void Func_5(){LCDDATA0 = 0b01101101;}   //5 を表示 //G = 1; F = 1; E = 0; D = 1; C = 1; B = 0; A = 1;
void Func_6(){LCDDATA0 = 0b01111101;}   //6 を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 1;
void Func_7(){LCDDATA0 = 0b00000111;}   //7 を表示 //G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 1;
void Func_8(){LCDDATA0 = 0b01111111;}   //8 を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;
void Func_9(){LCDDATA0 = 0b01101111;}   //9 を表示 //G = 1; F = 1; E = 0; D = 1; C = 1; B = 1; A = 1;
void Func_A(){LCDDATA0 = 0b01110111;}   //A を表示 //G = 1; F = 1; E = 1; D = 0; C = 1; B = 1; A = 1;
void Func_b(){LCDDATA0 = 0b01111100;}   //b を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 0;
void Func_C(){LCDDATA0 = 0b00111001;}   //C を表示 //G = 0; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;
void Func_d(){LCDDATA0 = 0b01011110;}   //d を表示 //G = 1; F = 0; E = 1; D = 1; C = 1; B = 1; A = 0;
void Func_E(){LCDDATA0 = 0b01111001;}   //E を表示 //G = 1; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;
void Func_F(){LCDDATA0 = 0b01110001;}   //F を表示 //G = 1; F = 1; E = 1; D = 0; C = 0; B = 0; A = 1;






#pragma interrupt my_Func               // 10msec タイマ1 インターバル割り込み

#pragma code isrcode = 0x08
void isr_direct(void)
{ _asm goto my_Func _endasm }
#pragma code

void my_Func(void)
{
        PIR1bits.TMR1IF = 0;    // タイマ1割り込みフラグをクリアする
         WriteTimer1(59286);    // 0.05μsec × 4 × 8 × 6250 = 10000μsec = 10msec (at システムクロック20MHz)
                                                        // 256×256 - 6250 = 59286
                                                        // タイマ0:16bitアップカウントタイマ → オーバーフローで割込み発生
        Count1++;
        if(Count1 >= 100)               //1秒毎に
        {
                Count1 = 0;
        
                if(Count2 == 0)Func_0();
                else if(Count2 == 1) Func_1();
                else if(Count2 == 2) Func_2();
                else if(Count2 == 3) Func_3();
                else if(Count2 == 4) Func_4();
                else if(Count2 == 5) Func_5();
                else if(Count2 == 6) Func_6();
                else if(Count2 == 7) Func_7();
                else if(Count2 == 8) Func_8();
                else if(Count2 == 9) Func_9();
                else if(Count2 == 10) Func_A();
                else if(Count2 == 11) Func_b();
                else if(Count2 == 12) Func_C();
                else if(Count2 == 13) Func_d();
                else if(Count2 == 14) Func_E();
                else  Func_F();

                Count2++;
                if(Count2 >= 16)Count2 = 0;

                if(LED == 1)
                {
                        PORTDbits.RD1 = 0;     // RD1 LED ON
                        LED = 0;
                }
                else
                {
                        PORTDbits.RD1 = 1;     // BポートのLED OFF
                        LED = 1;
                }

        }
}




void main (void)
{
        
        TRISCbits.RC1 = 1;      // RC1: in //HexSw
        TRISG = 0xFF;   //G port: in    //HexSw
        TRISD = 0x00;   //D port: out   //Segment Data
        TRISEbits.RE3 = 0;      //COM0: out
        TRISHbits.RH0 = 1;      //HexSw b0
        TRISHbits.RH2 = 0;      //LED free run


// LCDCON (LCD CONTROL)レジスタ

        LCDCONbits.SLPEN = 0;   //Sleep時のLCDドライバーモジュール イネーブル
        LCDCONbits.WERR = 0;    //No LCD Write Erro //LCD Write Failed Error bit
        LCDCONbits.CS1   = 0; //00 Fosc/4  1x INTRC(31KHz)   00 Sys Clock, 01 TMR1 Clk
        LCDCONbits.CS0   = 0; // 
        LCDCONbits.LMUX1 = 0;   //00 Static(COM0)スタティック制御  //Commons Select bis 
        LCDCONbits.LMUX0 = 0;

// LCDPS(LCD PHASE) レジスタ
        LCDPSbits.WFT     = 0;  //0 - TypeA(Phase changes whithin each common type)
        LCDPSbits.BIASMD  = 0;  //Bias Mode Select bit(スタティックモードでは0にセットのこと) 

        LCDPSbits.LCDA = 0;     //LCDドライバモジュールは非アクティブ
        LCDPSbits.WA = 0;       // LCDへの書き込みは許可されていない。

        LCDPSbits.LP3 = 0;              //0100LP <3:0> LCDクロックのプリスケーラ 1/5
        LCDPSbits.LP2 = 1;              //31000Hz / 5 = 6200Hz
        LCDPSbits.LP1 = 0;
        LCDPSbits.LP0 = 0;


// LCDSEx (LCD SEGMENT ENABLE)レジスタ
// 1: セグメント機能モード  0: I/Oモード
        LCDSE0 = 0xFF;  //対応ポート: SEG0-SEG7 //セグメント機能モード 
        LCDSE1 = 0x00;  //対応ポート: SEG8-SEG15//デジタルI/Oモード 
        LCDSE2 = 0x00;  //対応ポート: SEG16-SE23//デジタルI/Oモード  
        LCDSE3 = 0x00;  //対応ポート: SEG24-SEG31//デジタルI/Oモード  
        LCDSE4 = 0x00;  //対応ポート: SEG32-SEG39 //デジタルI/Oモード  
        LCDSE5 = 0x00;  //対応ポート: SEG40-SEG47 //デジタルI/Oモード  


 // LCDREG(VOLTAGE REGULATOR CONTROL)レジスタ
        LCDREGbits.CPEN   = 0;  //LCDチャージポンプOFF// LCD charge Pump Enable bit
        LCDREGbits.CKSEL1 = 0;  //Regulator Clock Source Select bit //LCD レギュレータ ディセーブル //
        LCDREGbits.CKSEL0 = 0;  //

        LCDCONbits.LCDEN = 1;   //LCDドライバーモジュール イネーブル   



        //タイマ1の設定 
        OpenTimer1
        (
                TIMER_INT_ON &  //割込み:ON
                T1_16BIT_RW &   //16 bit モードに設定  vs  8bit モード( T0_8BIT )
                T1_SOURCE_INT & //内部クロック使用
                T1_PS_1_8 &             //8ビットプリスケーラ  1/8 vs 1/1 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256 
                T1_OSC1EN_OFF
        );
                                                
        WriteTimer1(59286);

        RCONbits.IPEN = 0;              //割込み優先順位制御:OFF (RCON レジスタのIPENビット = 0)
        PIE1bits.TMR1IE = 1;               //タイマ1割込み許可
        INTCONbits.PEIE =1;             //周辺割込み許可 
                                                                //INTCONレジスタの b6ビット : 低位割込み許可/禁止(割り込み優先順位制御     有りの場合)                                  
        INTCONbits.GIE = 1;             //全割込み許可
                                                        //INTCONレジスタの b7ビット : 高位割込み許可/禁止(割り込み優先順位制御  有りの場合)





         while (1)
    {

    }


}





<動作結果>
 カウンタ値が3の場合の写真です。